package com.sjs.boot.dynamic.util;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONException;
import com.alibaba.fastjson.TypeReference;
import com.sjs.boot.dynamic.protocol.Const;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author uto_dev_008
 * @desc
 * @since 2021/11/9 20:51
 */
public class JsonUtil {
    private static final Logger LOG = LoggerFactory.getLogger(JsonUtil.class);

    /**
     * 把map或者是list转换成json字符串
     *
     * @param obj
     * @return 返回一个json
     */
    public static <T> byte[] mapToBytes(T obj) {
        try {
            return JSON.toJSONBytes(obj);
        } catch (Exception e) {
            LOG.error("Fail to convert into json", e);
            return null;
        }
    }

    /**
     * 把map或者是list转换成json字符串
     *
     * @param obj
     * @return 返回一个json
     */
    public static <T> String mapToJson(T obj) {
        try {
            return JSON.toJSONString(obj);
        } catch (Exception e) {
            LOG.error("Fail to convert into json", e);
            return null;
        }
    }


    /**
     * 把json字符串转成HashMap对象
     *
     * @param jsonBytes json值
     * @return 返回一个HashMap对象
     */
    public static Map<String, Object> jsonToMap(byte[] jsonBytes) {
        try {
            return JSON.parseObject(new String(jsonBytes, Const.DEFAULT_CHARSET), new TypeReference<Map<String, Object>>() {
            });
        } catch (Exception e) {
            LOG.error("Fail to parse json bytes", e);
            return null;
        }
    }

    /**
     * 把json字符串转成HashMap对象
     *
     * @param jsonStr json值
     * @return 返回一个HashMap对象
     */
    public static Map<String, Object> jsonToMap(String jsonStr) {
        try {
            return JSON.parseObject(jsonStr, new TypeReference<Map<String, Object>>() {
            });
        } catch (JSONException je) {
            String msg = je.getMessage();
            String indicator = "position at ";
            int start = msg.indexOf(indicator);
            if (start > 0) {
                int end = msg.indexOf(",", start);
                String sPos = msg.substring(start + indicator.length(), end);
                int pos = Integer.valueOf(sPos);
                start = pos > 10 ? (pos - 10) : 0;
                end = pos + 60 < jsonStr.length() ? (pos + 60) : jsonStr.length();
                LOG.error("Fail to parse json:{},\ncontent@[{},{}]:{}\n", msg, start, end, jsonStr.substring(start, end));
            } else {
                LOG.error("Fail to parse json string:{}", jsonStr, je);
            }
        } catch (Exception e) {
            LOG.error("Fail to parse json string:{}", jsonStr, e);
        }
        return null;
    }

    /**
     * 把json字符串转成List对象
     *
     * @param jsonStr json值
     * @return 返回一个List对象
     */
    public static List<Object> jsonToList(String jsonStr) {
        try {
            return JSON.parseObject(jsonStr, new TypeReference<List<Object>>() {
            });
        } catch (Exception e) {
            LOG.error("Fail to parse json string:{}", jsonStr, e);
            return null;
        }
    }

    /**
     * 把json文件转成HashMap对象
     *
     * @param jsonFile json值
     * @return 返回一个HashMap对象
     */
    public static Map<String, Object> jsonFileToMap(File jsonFile) {
        try {
            byte[] content = FileUtil.readFile(jsonFile);
            if (content == null || content.length <= 0) {
                return null;
            }
            String s = removeComment(new String(content, Const.DEFAULT_CHARSET));
            return jsonToMap(s);
        } catch (Exception e) {
            LOG.error("Fail to parse json file:{}", jsonFile.getAbsolutePath(), e);
            return null;
        }
    }

    public static List<Object> jsonFileToList(File jsonFile) {
        try {
            byte[] content = FileUtil.readFile(jsonFile);
            if (content == null || content.length <= 0) {
                return null;
            }
            String s = removeComment(new String(content, Const.DEFAULT_CHARSET));
            return JSON.parseObject(s, new TypeReference<List<Object>>() {
            });
        } catch (Exception e) {
            LOG.error("Fail to parse json file:{}", jsonFile.getAbsolutePath(), e);
            return null;
        }
    }

    enum CommentState {NORMAL, COMMMENT_START, MULTI_COMMENT, SIGNLE_COMMENT, COMMENT_ENDING, COMMENT_END, STR, SINGLE_STR}

    ;

    /**
     * 删除与C/C++/JAVA类似语法的注释内容
     * 用于删除json文档中的注释内容
     *
     * @param s
     * @return
     */
    public static String removeComment(String s) {
        int len = s.length();
        StringBuilder sb = new StringBuilder(len);
        char c;
        CommentState state = CommentState.NORMAL;

        for (int i = 0; i < len; i++) {
            c = s.charAt(i);
            switch (c) {
                case '/':
                    if (state == CommentState.NORMAL) {
                        state = CommentState.COMMMENT_START;
                    } else if (state == CommentState.COMMMENT_START) {
                        state = CommentState.SIGNLE_COMMENT;
                    } else if (state == CommentState.COMMENT_ENDING) {
                        state = CommentState.COMMENT_END;
                    }
                    break;
                case '*':
                    if (state == CommentState.COMMMENT_START) {
                        state = CommentState.MULTI_COMMENT;
                    } else if (state == CommentState.MULTI_COMMENT) {
                        state = CommentState.COMMENT_ENDING;
                    }
                    break;
                case '\r':
                case '\n':
                    if (state == CommentState.SIGNLE_COMMENT) {
                        state = CommentState.NORMAL;
                    } else if (state == CommentState.COMMENT_ENDING) {
                        state = CommentState.MULTI_COMMENT;
                    }
                    break;
                case '"':
                    if (state == CommentState.NORMAL) {
                        state = CommentState.STR;
                    } else if (state == CommentState.STR) {
                        state = CommentState.NORMAL;
                    }
                    break;
                case '\'':
                    if (state == CommentState.NORMAL) {
                        state = CommentState.SINGLE_STR;
                    } else if (state == CommentState.SINGLE_STR) {
                        state = CommentState.NORMAL;
                    }
                    break;
                default:
                    if (state == CommentState.COMMENT_ENDING) {
                        state = CommentState.MULTI_COMMENT;
                    }
                    break;
            }

            if (state == CommentState.NORMAL
                    || state == CommentState.STR
                    || state == CommentState.SINGLE_STR) {
                sb.append(c);
            } else if (state == CommentState.COMMENT_END) {
                state = CommentState.NORMAL;
            }
        }

        return sb.toString();
    }

    public static Map<String, Object> jsonStreamToMap(InputStream in) {
        return jsonStreamToMap(in, false);
    }

    public static Map<String, Object> jsonStreamToMap(InputStream in, boolean strict) {
        byte[] content = FileUtil.readStream(in);
        if (content == null || content.length <= 0) {
            return new HashMap<String, Object>();
        }
        return jsonToMap(new String(content, Const.DEFAULT_CHARSET));
    }
    //-------------------------------------------------------------------------

    /**
     * 合并多个map中的list，如果是非list，且dest中没有，则直接拷贝
     *
     * @param dest
     * @param src
     */
    @SuppressWarnings("unchecked")
    public static void mergeList(Map<String, Object> dest, Map<String, Object> src) {
        Object val;
        String key;

        for (Map.Entry<String, Object> one : src.entrySet()) {
            val = one.getValue();
            key = one.getKey();
            if (val != null && (val instanceof List<?>)) {
                List<Object> srcList = (List<Object>) val;
                List<Object> list = (List<Object>) dest.get(key);
                if (list == null) {
                    list = new ArrayList<Object>(srcList);
                } else {
                    list.addAll(srcList);
                }
                dest.put(key, list);
            } else {
                if (!dest.containsKey(key)) { //没有的情况才合入
                    dest.put(key, val);
                }
            }
        }
    }
}
